package com.googlecode.recycled.xml;

import com.google.common.collect.Iterables;
import org.xml.sax.ErrorHandler;
import org.xml.sax.SAXException;

import javax.xml.XMLConstants;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;
import java.io.IOException;
import java.io.InputStream;

public class XmlValidations {

    protected Schema schema;

    protected ObserverProxyErrorHandler observerProxyErrorHandler = new ObserverProxyErrorHandler();

    protected XmlValidations() {
    }

    public static XmlValidations newValidation(InputStream schema) {
        try {
            SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
            XmlValidations validations = new XmlValidations();
            validations.schema = factory.newSchema(new StreamSource(schema));
            return validations;
        } catch (SAXException e) {
            throw new RuntimeException(e);
        }
    }

    public XmlValidations addErrorHandler(ErrorHandler errorHandler) {
        observerProxyErrorHandler.addErrorHandler(errorHandler);
        return this;
    }

    public void validate(InputStream xml) {
        try {
            Validator validator = schema.newValidator();
            validator.setErrorHandler(observerProxyErrorHandler);
            validator.validate(new StreamSource(xml));
        } catch (SAXException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public Iterable<String> validateWithMessages(InputStream xml) {
        BufferedErrorHandler bufferedErrorHandler = new BufferedErrorHandler();
        observerProxyErrorHandler.addErrorHandler(bufferedErrorHandler);
        validate(xml);
        observerProxyErrorHandler.removeErrorHandler(bufferedErrorHandler);
        return Iterables.transform(bufferedErrorHandler.getParseExceptions(), new BufferedErrorHandler.EXCEPTION_TO_MESSAGE());
    }

}
